package DFA

import (
	"bytes"
	"html/template"
	"io"
	"io/ioutil"
	"strings"
)

type Info struct {
	S       string
	Sp      string
	Postfix string

	NFA  NFA
	DFA_ DFA
	DFA  DFA
}

type tqlData struct {
	S        string
	Sp       string
	Postfix  string
	NFAText  string
	DFATText string
	DFAText  string
}

// CreateMd 创建markdown文档并输出到 writer
func CreateMd(info *Info, writer io.Writer) error {
	var data = &tqlData{}
	data.S = info.S
	data.Sp = info.Sp
	data.Postfix = info.Postfix
	data.NFAText = drawNFA(info.NFA)
	data.DFATText = DrawDFA(info.DFA_)
	data.DFAText = DrawDFA(info.DFA)

	//载入模板并运行
	var buf = new(bytes.Buffer)
	var tql, err = template.ParseFiles("../template/res.tql")
	if err != nil {
		return err
	}
	if err := tql.Execute(buf, data); err != nil {
		return err
	}
	//去除转意
	var bDate, _ = ioutil.ReadAll(buf)
	st := string(bDate)
	st = strings.ReplaceAll(st, "--&gt;", "-->")
	st = strings.ReplaceAll(st, "&#34;", "\"")

	_, err = writer.Write([]byte(st))
	if err != nil {
		return err
	}
	return nil
}

// drawNFA 解析NFA 至字符串表示
func drawNFA(nfa NFA) string {
	var sb = strings.Builder{}
	// mp: 防止重复输出 保存节点名
	var mp = make(map[string]struct{})
	// tap: 换行和tap
	var tap = []byte{10, ' ', ' ', ' ', ' '}
	sb.WriteString("[*]-->")
	sb.WriteString(nfa.In().name)
	sb.Write(tap)
	sb.WriteString(nfa.Out().name)
	sb.WriteString(" -->[*]")
	sb.Write(tap)
	var nodes = make([]*node, 0, 100)
	nodes = append(nodes, nfa.In())
	// bfs
	for i := 0; i < len(nodes); i++ {
		for _, v := range nodes[i].edges {
			if _, ok := mp[v.name]; !ok {
				nodes = append(nodes, v)
				mp[v.name] = struct{}{}
				sb.WriteString(v.name)
				sb.Write(tap)
			}
		}
		for _, v := range nodes[i].any {
			if _, ok := mp[v.name]; !ok {
				nodes = append(nodes, v)
				mp[v.name] = struct{}{}
				sb.WriteString(v.name)
				sb.Write(tap)
			}
		}
	}
	for _, v := range nodes {
		for key, v1 := range v.edges {
			sb.WriteString(v.name + " --> " + v1.name + " :" + string(key))
			sb.Write(tap)
		}
		for _, v1 := range v.any {
			sb.WriteString(v.name + " --> " + v1.name + " : ε")
			sb.Write(tap)
		}
	}
	return sb.String()
}

// DrawDFA 解析DFA至字符串表示
func DrawDFA(dfa DFA) string {
	var sb = strings.Builder{}
	var tab = []byte{10, ' ', ' ', ' ', ' '}
	sb.WriteString("[*]-->")
	sb.WriteString(dfa.begin.name)
	sb.Write(tab)
	var finMp = make(map[string]struct{})
	for _, v := range dfa.end {
		finMp[v.name] = struct{}{}
	}
	for _, v := range dfa.states {
		if _, ok := finMp[v.name]; ok {
			sb.WriteString("state \"" + v.name + "\" as " + v.name)
		} else {
			sb.WriteString(v.name)
		}
		sb.Write(tab)

	}

	for _, v := range dfa.states {
		for key, val := range v.mp {
			sb.WriteString(v.name)
			sb.WriteString(" --> ")
			sb.WriteString(val)
			sb.WriteString(": " + string(key))
			sb.Write(tab)
		}
	}
	return sb.String()
}
